#region Using Statements
using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;

using Traffic.Path;
using Traffic.Graphics;

#endregion

namespace Traffic
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Traffic : Microsoft.Xna.Framework.Game
    {
       

        public enum GameStates {
            GAME_STOPPED,
            GAME_STARTED
        }

        private GameStates _gameState;
        public GameStates GameState
        {
            get { return _gameState; }
            set { _gameState = value; }
        }       

        GraphicsDeviceManager graphics;
        ContentManager content;      

        Texture2D grassTexture;
        

        Rectangle playArea;

        // The images will be drawn with this SpriteBatch
        static SpriteBatch spriteBatch;

        static SpriteFont spriteFont;

        // The cursor is used to tell what the user's pointer/mouse is over. The cursor
        // is moved with the left thumbstick. On windows, the mouse can be used as well.
        Cursor cursor;

        // PrimitiveBatch from the sample
        static PrimitiveBatch primitiveBatch;

       
        Road roadFixed;

        Control playButton;
        Control stopButton;

        Sprite car;      

        bool _drawDebug;


        public Traffic()
        {
            graphics = new GraphicsDeviceManager(this);
            content = new ContentManager(Services);

            cursor = new Cursor(this, content);
            Components.Add(cursor);

            playButton = new Control(this, content, cursor, new Vector2(50, 50), "Content/playbutton");
            Components.Add(playButton);
            stopButton = new Control(this, content, cursor, new Vector2(90, 50), "Content/resetbutton");
            Components.Add(stopButton);
            
            roadFixed = new Road();

            car = new Sprite();            

            _drawDebug = false;

            GameState = GameStates.GAME_STARTED;

        }


        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // Calculate safe bounds based on current resolution
            Viewport viewport = graphics.GraphicsDevice.Viewport;

            playArea = new Rectangle(0, 0, viewport.Width, viewport.Height);

            roadFixed.Add(new Vector2(50, 400));
            roadFixed.Add(new Vector2(200, 400));
            roadFixed.Add(new Vector2(300, 500));
            roadFixed.Add(new Vector2(330, 500));
            roadFixed.Add(new Vector2(400, 400));            
            roadFixed.Add(new Vector2(700, 100));

            
            this.car.Initialize();            
            this.car.Body.Position = new Vector2(20f, 380f);                       
            this.car.Body.Orientation = 0.8f;

            this.car.Body.MaxForce = 5000f;
            this.car.Body.Mass = 1f;
            this.car.Body.MaxVelocity = 150f;

            //this.InitIteratePath();

            base.Initialize();
        }


        /// <summary>
        /// Load your graphics content.  If loadAllContent is true, you should
        /// load content from both ResourceManagementMode pools.  Otherwise, just
        /// load ResourceManagementMode.Manual content.
        /// </summary>
        /// <param name="loadAllContent">Which type of content to load.</param>
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                grassTexture = content.Load<Texture2D>("Content/grass1");

                // Create a sprite batch to draw those textures
                spriteBatch = new SpriteBatch(graphics.GraphicsDevice);

                // Font used to draw
                spriteFont = content.Load<SpriteFont>("Content/Arial 14");

                primitiveBatch = new PrimitiveBatch(graphics.GraphicsDevice);

                Texture2D t;

                t = this.content.Load<Texture2D>("Content/playbutton");
                // ...and pass it to the Sprite object.
                this.car.LoadGraphicsContent(Traffic.spriteBatch, t);

            }

            // TODO: Load any ResourceManagementMode.Manual content
        }


        /// <summary>
        /// Unload your graphics content.  If unloadAllContent is true, you should
        /// unload content from both ResourceManagementMode pools.  Otherwise, just
        /// unload ResourceManagementMode.Manual content.  Manual content will get
        /// Disposed by the GraphicsDevice during a Reset.
        /// </summary>
        /// <param name="unloadAllContent">Which type of content to unload.</param>
        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            if (unloadAllContent)
            {
                // TODO: Unload any ResourceManagementMode.Automatic content
                content.Unload();                           
            }           
        }


        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {            
           
            // Get input
            KeyboardState keyboard = Keyboard.GetState();
            GamePadState gamePad = GamePad.GetState(PlayerIndex.One);

            // Allows the game to exit
            if (gamePad.Buttons.Back == ButtonState.Pressed ||
                keyboard.IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }

            if (playButton.Activated)
            {
                this.GameState = GameStates.GAME_STARTED;               
                playButton.Clear();
            }
            if (stopButton.Activated)
            {
                this.GameState = GameStates.GAME_STOPPED;
                stopButton.Clear();
            }

            // When game is stopped, sprites can be dragged
            if (this.GameState == GameStates.GAME_STOPPED)
            {
            }

            if (this.GameState == GameStates.GAME_STARTED)
            {
                // Steer vehicle towards mouse 
                //car.Body.SteerToward(cursor.Position);
                car.Body.FollowRoad(ref roadFixed);

                car.Update(gameTime);
            }
           
            


            base.Update(gameTime);
        }


        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
            
            GraphicsDevice device = graphics.GraphicsDevice;

            DrawBackground();

            DrawStatus();

            //DrawLines(ref roadFixed, Color.White);            

            // Draw objects
            spriteBatch.Begin();

            car.Draw(gameTime);

            spriteBatch.End();

            roadFixed.Draw();


            base.Draw(gameTime);
        }

        /// <summary>
        /// Draw vertices in arraylist
        /// </summary>
        /// <param name="al">ArrayList of vertices to draw</param>
        static public void DrawLines(ref List<Vector2> al, Color c)
        {
            // Draw the lines - vertices are in sequence
            if (al.Count > 1)
            {
                primitiveBatch.Begin(PrimitiveType.LineList);

                for (int i = 1; i < al.Count; i++)
                {
                    primitiveBatch.AddVertex((Vector2)al[i - 1], c);
                    primitiveBatch.AddVertex((Vector2)al[i], c);
                }

                primitiveBatch.End();
            }
        }

        static public void DrawLine(Vector2 v1, Vector2 v2, Color c)
        {
            primitiveBatch.Begin(PrimitiveType.LineList);
            primitiveBatch.AddVertex(v1, c);
            primitiveBatch.AddVertex(v2, c);
            primitiveBatch.End();           
        }
        
        /// <summary>
        /// Draw current game status, debug information
        /// </summary>
        private void DrawStatus()
        {
            //bool calculatePath = false;

            spriteBatch.Begin();
           
            // Print the mouse cursor position
            string postxt = "";

            if (_drawDebug)
            {
                if (playArea.Contains(new Point((int)cursor.Position.X, (int)cursor.Position.Y)))
                {
                    postxt = String.Format("Position {0},{1}", cursor.Position.X, cursor.Position.Y);
                }
                else
                {
                    postxt = "Out of bounds";
                }
            }

            if (this.GameState == GameStates.GAME_STARTED)
            {                                
                postxt = postxt + "STARTED";
            }
            else if (this.GameState == GameStates.GAME_STOPPED)
            {                                
                postxt = postxt + "STOPPED";
            }            

            if (_drawDebug)
            {
                float dist = Vector2.Distance(new Vector2(0, 0), cursor.Position);

                postxt += String.Format(" distance to corner {0}", dist);
            }

            spriteBatch.DrawString(spriteFont, postxt,
                       new Vector2(100, 100), Color.White, 0.0f,
                       new Vector2(0, 0), 1.0f, SpriteEffects.None, 0.0f);

            if (_drawDebug) 
            {
                // Find distances to all segments
                //float mindist = DistanceToRoad(roadFixed, cursor.Position);
                //string disttxt = String.Format("Distance to road: {0}", mindist);
                //spriteBatch.DrawString(spriteFont, disttxt,
                //           new Vector2(100, 130), Color.White, 0.0f,
                //           new Vector2(0, 0), 1.0f, SpriteEffects.None, 0.0f);

            }

            spriteBatch.End();

            //if (calculatePath)
            //{
            //    CalculatePath();
            //}
        }

        static public void DrawText(string txt, Vector2 pos, Color col)
        {              
            spriteBatch.DrawString(spriteFont, txt, pos, col);           
        }
      
        /// <summary>
        ///  Draw background graphics
        /// </summary>
        private void DrawBackground()
        {
            spriteBatch.Begin();


            int x, y;

            for (x = 0; x < playArea.Width; x += 100)
            {
                for (y = 0; y < playArea.Height; y += 100)
                {
                    spriteBatch.Draw(grassTexture, new Vector2(x, y), Color.White);
                }
            }

            spriteBatch.End();
        }        
    }
}
